package com.bckj.fastboot.iot.biz.service.impl;

import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.bckj.fastboot.core.lang.model.PageResult;
import com.bckj.fastboot.core.page.PageSupport;
import com.bckj.fastboot.iot.biz.repository.IotDeviceRepository;
import com.bckj.fastboot.iot.biz.service.IotDeviceDataQueryService;
import com.bckj.fastboot.iot.biz.service.IotProtocolDisplaySetService;
import com.bckj.fastboot.iot.common.constant.IotProtocolConstants;
import com.bckj.fastboot.iot.common.dto.query.IotBasicDataQuery;
import com.bckj.fastboot.iot.common.dto.query.IotDeviceDataQuery;
import com.bckj.fastboot.iot.common.dto.response.IotBasicDataResponse;
import com.bckj.fastboot.iot.common.dto.response.IotDeviceDataResponse;
import com.bckj.fastboot.iot.common.dto.response.LineDataResponse;
import com.bckj.fastboot.iot.common.entity.IotProtocolDisplaySet;
import com.bckj.fastboot.iot.common.repository.IotBasicDataRepository;
import com.bckj.fastboot.iot.common.repository.IotLiveDataRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

/**
 * IotDeviceDataQueryServiceImpl
 *
 * @author wfc
 **/
@Service
@RequiredArgsConstructor
public class IotDeviceDataQueryServiceImpl implements IotDeviceDataQueryService {

    private final IotDeviceRepository iotDeviceRepository;
    private final IotProtocolDisplaySetService iotProtocolDisplaySetService;
    private final IotLiveDataRepository iotLiveDataRepository;
    private final IotBasicDataRepository iotBasicDataRepository;

    @Override
    public List<IotDeviceDataResponse> findDataList(IotDeviceDataQuery query) {
        return iotDeviceRepository.getBaseMapper().findDataList(query);
    }

    @Override
    public PageResult<IotDeviceDataResponse> page(IPage<IotDeviceDataResponse> page, IotDeviceDataQuery query) {
        var result = PageSupport.page(page, () -> findDataList(query));
        result.getRecords().forEach(this::handleDataList);
        return PageResult.of(result);
    }

    private void handleDataList(IotDeviceDataResponse data) {
        List<IotProtocolDisplaySet.Item> list = iotProtocolDisplaySetService.getItems(data.getDevModel(), IotProtocolConstants.DISPLAY_SET_TYPE_LIST);
        Map<String, Object> dataMap = iotLiveDataRepository.get(data.getDevCode());
        var dataList = getDataList(list, dataMap);
        data.setDataList(dataList);
    }

    @Override
    public IotDeviceDataResponse realData(IotDeviceDataQuery query) {
        String devModel = query.getDevModel();
        String devCode = query.getDevCode();
        List<IotProtocolDisplaySet.Item> list = iotProtocolDisplaySetService.getItems(devModel, IotProtocolConstants.DISPLAY_SET_TYPE_REALTIME);
        Map<String, Object> dataMap = iotLiveDataRepository.get(devCode);
        var dataList = getDataList(list, dataMap);
        var result = new IotDeviceDataResponse();
        result.setDataList(dataList);
        return result;
    }

    @Override
    public PageResult<IotDeviceDataResponse> historyData(Pageable page, IotDeviceDataQuery query) {
        IotBasicDataQuery basicDataQuery = convert(query);
        PageResult<IotBasicDataResponse> result = iotBasicDataRepository.page(page, basicDataQuery);
        var list = iotProtocolDisplaySetService.getItems(query.getDevCode(), IotProtocolConstants.DISPLAY_SET_TYPE_HISTORY);
        return result.convert(p -> {
            var response = new IotDeviceDataResponse();
            var dataList = getDataList(list, p.getDataMap());
            response.setDataList(dataList);
            return response;
        });
    }

    @Override
    public IotDeviceDataResponse lineData(IotDeviceDataQuery query) {
        IotBasicDataQuery basicDataQuery = convert(query);
        List<IotBasicDataResponse> result = iotBasicDataRepository.findList(basicDataQuery);
        var list = iotProtocolDisplaySetService.getItems(query.getDevCode(), IotProtocolConstants.DISPLAY_SET_TYPE_LINE);
        Map<String, LineDataResponse> lineDataMap = MapUtil.newHashMap();
        for (IotBasicDataResponse data : result) {
            for (IotProtocolDisplaySet.Item item : list) {
                String protocolCode = item.getProtocolCode();
                Object dataValue = data.getDataMap().get(protocolCode);
                var lineData = lineDataMap.computeIfAbsent(protocolCode, k -> LineDataResponse.of());
                lineData.getLineList().add(MapUtil.<String, Object>builder()
                        .put("time", data.getCollectionTime())
                        .put("dataValue", dataValue)
                        .build());
            }
        }
        var response = new IotDeviceDataResponse();
        response.setLineDataMap(lineDataMap);
        return response;
    }

    private IotBasicDataQuery convert(IotDeviceDataQuery query) {
        var basicDataQuery = new IotBasicDataQuery();
        basicDataQuery.setDevCode(query.getDevCode());
        basicDataQuery.setStartTime(query.getStartTime());
        basicDataQuery.setEndTime(query.getEndTime());
        return basicDataQuery;
    }

    private List<Map<Object, Object>> getDataList(
            List<IotProtocolDisplaySet.Item> list,
            Map<String, Object> dataMap) {
        return list.stream()
                .map(p -> {
                    Object dataValue = dataMap.get(p.getProtocolCode());
                    String dataValueStr = null;
                    if (dataValue != null) {
                        dataValueStr = dataValue + p.getUnit();
                    }
                    return MapUtil.builder()
                            .put("protocolName", p.getProtocolName())
                            .put("protocolCode", p.getProtocolCode())
                            .put("description", p.getDescription())
                            .put("dataValue", dataValueStr)
                            .build();
                }).toList();
    }

}
